import 'dart:async';

import 'package:rxdart/rxdart.dart';

import '../../common/test_page.dart';
import '../utils.dart';

class ScanTestPage extends TestPage {
  ScanTestPage(super.title) {
    test('Rx.scan', () async {
      const expectedOutput = [1, 3, 6, 10];
      var count = 0;

      Stream.fromIterable(const [1, 2, 3, 4])
          .scan<int>((acc, value, index) => acc + value, 0)
          .listen(((result) {
        expect(expectedOutput[count++]);
      }));
    });

    test('Rx.scan.nullable', () {
      nullableTest<String?>(
            (s) => s.scan((acc, value, index) => acc, null),
      );

      expect(
        Stream.fromIterable(const [1, 2, 3, 4])
            .scan<int?>((acc, value, index) => (acc ?? 0) + value, null)
            .cast<int>(),
      );
    });

    test('Rx.scan.reusable', () async {
      final transformer =
      ScanStreamTransformer<int, int>((acc, value, index) => acc + value, 0);
      const expectedOutput = [1, 3, 6, 10];
      var countA = 0, countB = 0;

      Stream.fromIterable(const [1, 2, 3, 4])
          .transform(transformer)
          .listen(((result) {
        expect(expectedOutput[countA++]);
      }));

      Stream.fromIterable(const [1, 2, 3, 4])
          .transform(transformer)
          .listen(((result) {
        expect(expectedOutput[countB++]);
      }));
    });

    test('Rx.scan.asBroadcastStream', () async {
      final stream = Stream.fromIterable(const [1, 2, 3, 4])
          .asBroadcastStream()
          .scan<int>((acc, value, index) => acc + value, 0);


      stream.listen(null);
      stream.listen(null);

      expect(true);
    });

    test('Rx.scan.error.shouldThrow', () async {
      final streamWithError = Stream.fromIterable(const [1, 2, 3, 4])
          .scan((acc, value, index) => throw StateError('oh noes!'), 0);

      streamWithError.listen(null,
          onError: (Object e, StackTrace s) {
            expect(e);
          });
    });

    test('Rx.scan accidental broadcast', () async {
      final controller = StreamController<int>();

      final stream =
      controller.stream.scan<int>((acc, value, index) => acc + value, 0);

      stream.listen(null);
      expect(() => stream.listen(null));

      controller.add(1);
    });
  }

}